package club.xyes.zkh.ecommerce.web.api.controller;

import club.xyes.zkh.ecommerce.commons.context.ApplicationConstants;
import club.xyes.zkh.ecommerce.commons.dto.MinimalShopInfo;
import club.xyes.zkh.ecommerce.commons.entity.*;
import club.xyes.zkh.ecommerce.commons.exception.BadRequestException;
import club.xyes.zkh.ecommerce.commons.properties.WebsiteConfigurationProperties;
import club.xyes.zkh.ecommerce.commons.util.EntityImagePathUtils;
import club.xyes.zkh.ecommerce.commons.util.QrCodeUtil;
import club.xyes.zkh.ecommerce.commons.util.TextUtil;
import club.xyes.zkh.ecommerce.commons.vo.GeneralResult;
import club.xyes.zkh.ecommerce.security.encoder.AccessTokenEncoder;
import club.xyes.zkh.ecommerce.service.*;
import club.xyes.zkh.ecommerce.web.api.vo.ShopLoginVo;
import club.xyes.zkh.ecommerce.web.controller.BaseController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Create by 郭文梁 2019/4/17 0017 11:00
 * ShopController
 * 店铺相关数据访问控制器
 *
 * @author 郭文梁
 * @data 2019/4/17 0017
 */
@RestController
@RequestMapping("/api/shop")
@Api("店铺相关API接口")
public class ShopController extends BaseController<Shop> {
    private final ShopService service;
    private final UserService userService;
    private final WebsiteConfigurationProperties websiteConfigurationProperties;
    private final ShopImageService shopImageService;
    private final UserCollectShopService userCollectShopService;
    private final UserCouponService userCouponService;
    private final UserMembershipService userMembershipService;
    private final AccessTokenEncoder accessTokenEncoder;

    @Autowired
    public ShopController(ShopService service,
                          UserService userService,
                          WebsiteConfigurationProperties websiteConfigurationProperties,
                          ShopImageService shopImageService,
                          UserCollectShopService userCollectShopService,
                          UserCouponService userCouponService,
                          UserMembershipService userMembershipService,
                          AccessTokenEncoder accessTokenEncoder) {
        super(service);
        this.service = service;
        this.userService = userService;
        this.websiteConfigurationProperties = websiteConfigurationProperties;
        this.shopImageService = shopImageService;
        this.userCollectShopService = userCollectShopService;
        this.userCouponService = userCouponService;
        this.userMembershipService = userMembershipService;
        this.accessTokenEncoder = accessTokenEncoder;
    }

    /**
     * 设置商铺Logo
     *
     * @param id       店铺ID
     * @param logoFile logo文件
     * @return Shop
     * @throws IOException IOE
     */
    @PostMapping("/{id:\\d+}/_set-logo")
    @ApiOperation("上传/修改商铺Logo")
    public GeneralResult<Shop> setLogo(@ApiParam(value = "商铺ID", example = "1") @PathVariable("id") Integer id,
                                       @ApiParam("Logo图片") MultipartFile logoFile) throws IOException {
        if (logoFile == null || logoFile.isEmpty()) {
            return GeneralResult.badRequest("Logo file could not be empty!");
        }
        Shop shop = service.setLogo(id, logoFile);
        EntityImagePathUtils.prettyLogoPath(shop,
                websiteConfigurationProperties.getStaticServerPrefix(),
                websiteConfigurationProperties.getShopLogoPath());
        return GeneralResult.ok(shop);
    }

    /**
     * 更新商铺数据
     *
     * @param paramShop {name, phone address dailyHours}
     * @return GeneralResult
     */
    @ApiOperation("更新商铺信息")
    @PostMapping("/_update")
    public GeneralResult<Shop> update(@RequestBody Shop paramShop) {
        checkUpdateParams(paramShop);
        Shop shop = currentShop(service);
        setUpdateParam2Shop(shop, paramShop);
        Shop res = service.updateById(shop);
        EntityImagePathUtils.prettyLogoPath(res,
                websiteConfigurationProperties.getStaticServerPrefix(),
                websiteConfigurationProperties.getShopLogoPath());
        return GeneralResult.ok(res);
    }

    /**
     * 店铺概览信息
     *
     * @param id 店铺ID
     * @return GeneralResult
     */
    @ApiOperation("用户店铺概览信息")
    @GetMapping("/{id}/overview")
    public GeneralResult<Map<String, Object>> detail(@PathVariable("id") Integer id) {
        Shop shop = service.getRequired(id);
        String serverPrefix = websiteConfigurationProperties.getStaticServerPrefix();
        String shopLogoPath = websiteConfigurationProperties.getShopLogoPath();
        String shopImagePath = websiteConfigurationProperties.getShopImagePath();
        String membershipImagePath = websiteConfigurationProperties.getShopMembershipImagePath();
        List<ShopImage> images = shopImageService.findByShopId(id);
        EntityImagePathUtils.prettyLogoPath(shop, serverPrefix, shopLogoPath);
        images = EntityImagePathUtils.prettyShopImagePath(images, serverPrefix, shopImagePath);
        List<UserMembership> membership = userMembershipService.findByUserIdAndShopIdFetchAll(getRequiredUserInfo().getUserId(), shop.getId()).stream()
                .peek(um -> EntityImagePathUtils.prettyShopMembershipImagePath(um.getLevel().getMembership(), serverPrefix, membershipImagePath))
                .collect(Collectors.toList());
        boolean collected = userCollectShopService.isCollected(getRequiredUserInfo().getUserId(), id);
        Map<String, Object> res = new HashMap<>(4);
        res.put("shop", shop);
        res.put("images", images);
        res.put("collected", collected);
        res.put("membership", membership);
        return GeneralResult.ok(res);
    }

    /**
     * 当前商铺的概览信息
     *
     * @return GR
     */
    @ApiOperation("当前店铺的详细信息")
    @GetMapping("/overview")
    public GeneralResult<Map<String, Object>> detail() {
        Shop shop = currentShop(service);
        List<ShopImage> images = shopImageService.findByShopId(shop.getId());
        String serverPrefix = websiteConfigurationProperties.getStaticServerPrefix();
        String shopLogoPath = websiteConfigurationProperties.getShopLogoPath();
        String shopImagePath = websiteConfigurationProperties.getShopImagePath();
        String shopPromotionImagePath = websiteConfigurationProperties.getShopPromotionImagePath();
        EntityImagePathUtils.prettyLogoPath(shop, serverPrefix, shopLogoPath);
        EntityImagePathUtils.prettyShopPromotionImagePath(shop, serverPrefix, shopPromotionImagePath);
        images = EntityImagePathUtils.prettyShopImagePath(images, serverPrefix, shopImagePath);
        Map<String, Object> res = new HashMap<>(2);
        res.put("shop", shop);
        res.put("images", images);
        return GeneralResult.ok(res);
    }

    /**
     * 支付时 获取商铺的概览信息
     * 商铺基本信息
     * 用户所拥有的优惠券
     * 用户的会员等级
     *
     * @param id 商铺ID
     * @return GR
     */
    @ApiOperation("支付时商铺的概览信息")
    @GetMapping("/{id}/payment-overview")
    public GeneralResult<Map<String, Object>> paymentOverview(@PathVariable Integer id) {
        Map<String, Object> res = new HashMap<>(3);
        User user = userService.getRequired(getRequiredUserInfo().getUserId());
        Shop shop = service.getRequired(id);
        List<UserCoupon> coupons = userCouponService.findByUserAndShop(user, shop);
        List<UserMembership> levels = userMembershipService.findByUserIdAndShopIdFetchAll(user.getId(), shop.getId());
        String serverPrefix = websiteConfigurationProperties.getStaticServerPrefix();
        String shopLogoPath = websiteConfigurationProperties.getShopLogoPath();
        String membershipImagePath = websiteConfigurationProperties.getShopMembershipImagePath();
        String couponImagePath = websiteConfigurationProperties.getCouponImagePath();
        EntityImagePathUtils.prettyLogoPath(shop, serverPrefix, shopLogoPath);
        levels = levels.stream()
                .peek(level -> EntityImagePathUtils.prettyShopMembershipImagePath(level.getLevel().getMembership(), serverPrefix, membershipImagePath))
                .collect(Collectors.toList());
        coupons = coupons.stream()
                .peek(coupon -> EntityImagePathUtils.prettyCouponImagePath(coupon.getCoupon(), serverPrefix, couponImagePath))
                .collect(Collectors.toList());
        res.put("shop", shop);
        res.put("coupons", coupons);
        res.put("level", levels);
        return GeneralResult.ok(res);
    }

    /**
     * 更新商铺信息
     *
     * @param paramShop          (dailyHours, province, city, region, address, phone)
     * @param logoFile           logo图片
     * @param imageFiles         轮播图
     * @param promotionImageFile 促销图片
     * @return GR
     * @throws IOException IO异常
     */
    @ApiOperation("更新商铺信息")
    @PostMapping("/update-all")
    public GeneralResult<Map<String, Object>> update(
            Shop paramShop,
            MultipartFile logoFile,
            MultipartFile[] imageFiles,
            MultipartFile promotionImageFile) throws IOException {
        //检查参数
        checkUpdateParams(paramShop);
        //查询商铺
        Shop shop = currentShop(service);
        //设置参数
        setUpdateParam2Shop(shop, paramShop);
        //更新商铺
        Map<String, Object> context = new HashMap<>(4);
        shop = service.updateById(shop);
        shop = updateLogoAndPromotionImage(shop, logoFile, promotionImageFile, context);
        resetShopImage(shop, imageFiles, context);
        context.put("shop", shop);
        return GeneralResult.ok(context);
    }

    /**
     * 重新设置商铺轮播图
     *
     * @param shop       商铺
     * @param imageFiles 轮播图数组
     * @param context    上下文
     * @return Shop
     * @throws IOException IO异常
     */
    @SuppressWarnings("all")
    private Shop resetShopImage(Shop shop, MultipartFile[] imageFiles, Map<String, Object> context) throws IOException {
        if (imageFiles == null) {
            context.put("shopImagesMsg", "未更新商铺轮播图");
            return shop;
        }
        List<MultipartFile> files = Arrays.stream(imageFiles)
                .filter(file -> file != null && !file.isEmpty())
                .collect(Collectors.toList());
        if (files.size() <= 0) {
            context.put("shopImagesMsg", "未更新商铺轮播图");
            return shop;
        }
        List<ShopImage> images = shopImageService.resetShopImage(shop, files);
        context.put("shopImages", images);
        return shop;
    }

    /**
     * 更新shop logo 和促销图片
     *
     * @param shop     商铺对象
     * @param logoFile logo文件
     * @return Shop
     * @throws IOException IO异常
     */
    private Shop updateLogoAndPromotionImage(Shop shop, MultipartFile logoFile,
                                             MultipartFile promotionImageFile,
                                             Map<String, Object> context) throws IOException {
        if (logoFile == null || logoFile.isEmpty()) {
            context.put("shopLogoMsg", "未更新商铺Logo");
        } else {
            shop = service.setLogo(shop.getId(), logoFile);
        }
        if (promotionImageFile == null || promotionImageFile.isEmpty()) {
            context.put("promotionImageMsg", "未更新促销图片");
        } else {
            shop = service.setPromotionImage(shop, promotionImageFile);
        }
        return shop;
    }

    /**
     * 设置参数
     *
     * @param shop      目标对象
     * @param paramShop 参数对象
     */
    private void setUpdateParam2Shop(Shop shop, Shop paramShop) {
        shop.setDailyHours(paramShop.getDailyHours());
        shop.setProvince(paramShop.getProvince());
        shop.setCity(paramShop.getCity());
        shop.setRegion(paramShop.getRegion());
        shop.setAddress(paramShop.getAddress());
        shop.setPhone(paramShop.getPhone());
    }

    /**
     * 检查更新数据时的商铺参数
     *
     * @param shop 商铺
     */
    private void checkUpdateParams(Shop shop) {
        if (shop == null) {
            throw new BadRequestException("请完善必填参数");
        }
        if (TextUtil.isTrimedEmpty(shop.getDailyHours())) {
            throw new BadRequestException("营业时间未填");
        }
        if (TextUtil.isTrimedEmpty(shop.getProvince())
                || TextUtil.isTrimedEmpty(shop.getCity())
                || TextUtil.isTrimedEmpty(shop.getRegion())) {
            throw new BadRequestException("省市区未填");
        }
        if (TextUtil.isTrimedEmpty(shop.getAddress())) {
            throw new BadRequestException("详细地址未填");
        }
        if (TextUtil.isTrimedEmpty(shop.getPhone())) {
            throw new BadRequestException("服务电话未填");
        }
    }

    /**
     * 设置商家促销图片
     *
     * @param shopId        商铺ID
     * @param promotionFile 促销图片
     * @return GR
     * @throws IOException IO异常
     */
    @PostMapping("/{shopId}/set-promotion")
    @ApiOperation("设置活动图片")
    public GeneralResult<Shop> setPromotionImage(@PathVariable("shopId") Integer shopId,
                                                 MultipartFile promotionFile) throws IOException {
        if (promotionFile == null || promotionFile.isEmpty()) {
            return GeneralResult.badRequest("未上传图片");
        }
        Shop shop = service.getRequired(shopId);
        shop = service.setPromotionImage(shop, promotionFile);
        return GeneralResult.ok(shop);
    }

    /**
     * 商家登录
     *
     * @param param {loginName, password, code}
     * @return GR
     */
    @PostMapping("/login")
    @ApiOperation("商铺登录")
    public GeneralResult<Map<String, Object>> login(@RequestBody ShopLoginVo param) {
        checkLoginParam(param);
        Shop shop = service.login(param.getLoginName(), param.getPassword(), param.getCode());

        MinimalShopInfo shopInfo = MinimalShopInfo.fromShop(shop);
        String accessToken = accessTokenEncoder.encode(shopInfo.toJson(), ApplicationConstants.Security.TOKEN_SHOP_PREFIX);

        Map<String, Object> res = new HashMap<>(2);

        prettyPath(websiteConfigurationProperties, shop);
        res.put("shop", shop);
        res.put("accessToken", accessToken);
        return GeneralResult.ok(res);
    }

    /**
     * 获取商铺的token 测试时使用
     *
     * @param id id
     * @return GR
     */
    @GetMapping("/{id}/token")
    @ApiOperation("当前商铺的Token")
    public GeneralResult<String> token(@PathVariable("id") Integer id) {
        Shop shop = service.getRequired(id);
        MinimalShopInfo shopInfo = MinimalShopInfo.fromShop(shop);
        String token = accessTokenEncoder.encode(shopInfo.toJson(), ApplicationConstants.Security.TOKEN_SHOP_PREFIX);
        return GeneralResult.ok(token);
    }

    /**
     * 自动登录接口
     *
     * @param param (code)
     * @return GR
     */
    @ApiOperation("自动登录接口")
    @PostMapping("/auto-login")
    public GeneralResult<Shop> autoLogin(@RequestBody ShopLoginVo param) {
        if (param == null || TextUtil.isTrimedEmpty(param.getCode())) {
            return GeneralResult.badRequest("参数code未传");
        }
        String code = param.getCode();
        Shop shop = service.loginByCode(code);
        prettyPath(websiteConfigurationProperties, shop);
        return GeneralResult.ok(shop);
    }

    /**
     * 检查登录参数
     *
     * @param param 参数
     */
    private void checkLoginParam(ShopLoginVo param) {
        if (param == null) {
            throw new BadRequestException("未传入参数");
        }
        if (TextUtil.isTrimedEmpty(param.getLoginName())
                || TextUtil.isTrimedEmpty(param.getPassword())
                || TextUtil.isTrimedEmpty(param.getCode())) {
            throw new BadRequestException("缺少参数");
        }
    }

    /**
     * 获取当前商铺的二维码
     *
     * @return RE
     */
    @GetMapping("/qr-code")
    @ApiOperation("获取当前商铺的二维码")
    public GeneralResult<String> getMyQrCode() {
        Shop shop = currentShop(service);
        String qrCodeContent = String.format("https://wz.jinguanjiazhifu.com/ecommerce/mp/%s", shop.getId());
        byte[] result = QrCodeUtil.creatRrCode(qrCodeContent, 500, 500);
        String base64 = Base64Utils.encodeToString(result);
        return GeneralResult.ok(base64);
    }

    /**
     * 商家登出接口
     *
     * @return GR
     */
    @PostMapping("/logout")
    @ApiOperation("商家登出")
    public GeneralResult<Shop> logout() {
        Shop shop = currentShop(service);
        shop.setWxOpenId(null);
        Shop res = service.updateById(shop);
        return GeneralResult.ok(res);
    }

    /**
     * 商铺详细信息 /api/shop/{id}/detail
     * @param id 商铺ID
     * @return GR
     */
    @GetMapping("/{id}/detail")
    @ApiOperation("商铺详细信息")
    public GeneralResult<Shop> detailWithPath(@PathVariable("id") Integer id) {
        Shop shop = service.getRequired(id);
        String serverPrefix = websiteConfigurationProperties.getStaticServerPrefix();
        String shopLogoPath = websiteConfigurationProperties.getShopLogoPath();
        EntityImagePathUtils.prettyLogoPath(shop, serverPrefix, shopLogoPath);
        return GeneralResult.ok(shop);
    }
}
